#include "assert.h"
#include "error.h"
#include "fs/deffs.h"
#include "fs/inode.h"
#include "fs/iobuf.h"
#include "fs/vfs.h"
#include "proc.h"
#include "type.h"



static inline inode_t*
getCwdNolock(void) {
    return getCurrentProc()->fp->pwd;
}

static inline void
setCwdNolock(inode_t* pwd) {
    getCurrentProc()->fp->pwd = pwd;
}

static inline void
lockCfs(void) {
    lockFiles(getCurrentProc()->fp);
}

static inline void
unlockCfs(void) {
    unlockFiles(getCurrentProc()->fp);
}

int
vfs_getCurrentDir(inode_t** dir_store) {
    inode_t* node = getCwdNolock();
    if (node != NULL) {
        vop_refInc(node);
        *dir_store = node;
        return 0;
    }
    return -E_NOENTRY;
}

int
vfs_setCurrentDir(inode_t* dir) {
    int ret = 0;
    inode_t* oldDir;
    lockCfs();
    oldDir = getCwdNolock();
    if (oldDir != dir) {
        if (dir != NULL) {  //需要更改目录的正常情况
            uint32_t type;
            ret = vop_getType(dir, &type);
            if (ret != 0)
                goto out;

            if (!S_ISDIR(type)) {
                ret = E_NOTDIR;
                goto out;
            }
            vop_refInc(dir);
        }
        setCwdNolock(dir);
        if (oldDir != NULL)
            vop_refDec(oldDir);
    }

out:
    unlockCfs();
    return ret;
}

int
vfs_chdir(char* path) {
    inode_t* node;
    int ret = vfs_lookup(path, &node);
    if (ret == 0) {
        ret = vfs_setCurrentDir(node);
        vop_refDec(node);  //?
    }
    return ret;
}

int
vfs_getcwd(iobuf_t* iob) {  //?
    inode_t* node;
    int ret = vfs_getCurrentDir(&node);
    if (ret != 0)
        return ret;
    assert(node->inodeFS != NULL);

    const char* devName = vfs_getDeviceName(node->inodeFS);
    ret = iobuf_move(iob, (char*)devName, strlen(devName), 1, NULL);
    if (ret != 0)
        goto out;

    char colon = ':';
    ret = iobuf_move(iob, &colon, sizeof(colon), 1, NULL);
    if (ret != 0)
        goto out;

    ret = vop_nameFile(node, iob);

out:
    vop_refDec(node);
    return ret;
}